#include "Level.h"


Level::Level(Joueur* j,TextManager* txtmngr):j_(j),txtmngr_(txtmngr)
{

    j_=j;  //On initiallise le personnage avant de créer le niveau car on place le joueur sur le départ dans la fonction randomLevelGenerator
    m_=new Map();
    v_=new Vision(m_);
    addRandomNonJoueur();

}


Level::~Level()
{
    //dtor
}
//Dessine la carte à l'écran
void Level::draw()
{

    Affichage::effaceTout();
    updatePosition();
    for(int y=0;y<NY;y++){
        for(int x=0;x<NX;x++){
            if(v_->getVisibilite(x,y)){
                if(projectile_[y][x])
                    Affichage::affiche('o');
                else if(persoNiveau_[y][x]==-1)
                    j_->draw();
                else if (persoNiveau_[y][x]==-2)
                    m_->drawPos(x,y);

                else if (persoNiveau_[y][x]>=0)
                    p_[persoNiveau_[y][x]]->draw();
            }else
                Affichage::affiche(' ');

        }
        Affichage::sautLigne();
    }

}

//Met à jour la position des personnages sur la carte dans le tableau niveauPerso_
void Level::updatePerso()
{
    gererCollisionJoueur();
    gererMort();
    v_->setVisibilite(j_->getPos());

    updatePosition();
}
void Level::updatePosition()
{
    map<int,NonJoueur*>::iterator it;
    resetPersoNiveau();
    persoNiveau_[j_->getY()][j_->getX()]=-1;
    for(it=p_.begin();it!=p_.end();++it){
       persoNiveau_[it->second->getY()][it->second->getX()]=it->first;

    }

}
void Level::iaNonJoueur()
{
    map<int,NonJoueur*>::iterator it;
    for(it=p_.begin();it!=p_.end();++it){
       it->second->ia(j_,m_);

    }
    gererCollisionNonJoueur();
    gererMort();

}
//Supprime les anciennes position des personnages (mets des 0)
void Level::resetPersoNiveau()
{
    for(int x=0;x<NX;x++){
        for(int y=0;y<NY;y++){
            persoNiveau_[y][x]=-2;
        }
    }
}
//Deplacer le personnage en verifiant qu'il n'y a pas de mur
//string lastCommand est la dernière commande entrée
bool Level::movePerso(int lastCommand)
{
    position a=j_->getPos();

        switch(lastCommand){
            case 0:
                j_->deplacer(0);
            break;
            case 1:
                j_->deplacer(1);
            break;
            case 2:
                j_->deplacer(2);
            break;
            case 3:
                j_->deplacer(3);
            break;
            case 4:
            if(m_->isChgt(a)){
                changeLevel_=true;
                type_change_=m_->chgtType(a);
            }
            break;
            case 5:
                v_->changeVisionCheat();
            break;
            default:
            break;
        }
    updatePerso();
    return false;
}


Joueur* Level::getJoueur()       //retourne le pointeur qui pointe sur le joueur
{
    return j_;

}
void Level::moveJoueurSpawn() //Deplace le joueur au spawn
{

    j_->deplacer(m_->getSpawn());
    j_->setLastPos(m_->getSpawn());
    updatePerso();
}
void Level::moveJoueurFin() //Deplace le joueur à la fin du niveau
{

    j_->deplacer(m_->getFin());
    j_->setLastPos(m_->getFin());
    updatePerso();
}
void Level::moveJoueurPorte(int porte) //Deplace le joueur à la porte1
{

    j_->deplacer(m_->getPorte(porte));
    j_->setLastPos(m_->getPorte(porte));
    updatePerso();
}
 void Level::changedLevel(Type_Edge b)  //On vient de changer de level et on réatterit sur celui ci
 {
    changeLevel_=false;
    switch(b){
        case ESC_DES:
            moveJoueurSpawn();
        break;
        case ESC_MON:
            moveJoueurFin();
        break;
        case PORTE1:
            moveJoueurPorte(1);
        break;
        case PORTE2:
            moveJoueurPorte(2);
    }

 }
void Level::addNonJoueur(int x, int y)
{
    p_[p_.size()]=new NonJoueur(x,y,p_.size(),txtmngr_);

}
void Level::addRandomNonJoueur()
{
    for(int i=0;i<randab(2,4);i++){
        position p=m_->randomPositionInterieur();
        addNonJoueur(p.x,p.y);
    }
}
void Level::gererAttaqueSurEnnemis(int id)
{

    Personnage* a=p_[id];
    string d=a->recevoirAttaque(j_->getDegats(),j_->getScore());

    txtmngr_->addMessage("Vous avez attaqué un ennemi, "+d);
}
void Level::gererAttaqueDeEnnemis(int id)
{
    Personnage* a=p_[id];
    txtmngr_->addMessage("COMBAT: Degats "+TextManager::to_string(1));
}
void Level::gestionAttaqueDistJoueur(direction a)
{
    int id=persoSurLigne(a);
    if(id!=-2 && m_->checkLOS(j_->getPos(),p_[id]->getPos())){
        for(int i=0;i<j_->getArme()->getTirTour();i++){
            gererAttaqueSurEnnemis(id);
        }
        animerProjectile(j_->getPos(),p_[id]->getPos(),a);
    }else{
        txtmngr_->addMessage("Aucun ennemis à portée");
    }

}
int Level::persoSurLigne(direction a)
{
    int dx=0,dy=0;
    int retour=-2;
    convertDir(dx,dy,a);
    int x=j_->getX();
    int y=j_->getY();

        for(y=j_->getY()+dy,x=j_->getX()+dx;(y>=0 && y<NY && x>=0 && x<NX );y+=dy,x+=dx){
            if(persoNiveau_[y][x]!=-2){

                return persoNiveau_[y][x];

            }

        }

    return -2;
}
void Level::convertDir(int &dx,int &dy,direction a)
{

    switch(a){
        case HAUT:
            dy=-1;
        break;
        case BAS:
            dy=1;
        break;
        case GAUCHE:
            dx=-1;
        break;
        case DROITE:
            dx=1;
        break;
    }

}
void Level::gererCollisionJoueur()
{
    map<int,NonJoueur*>::iterator itr;
    if(!(m_->estAccessible(j_->getPos()))){
        j_->collisionMap();
        }
        for(itr=p_.begin();itr!=p_.end();++itr){
            if( itr->second->getPos()==j_->getPos()){

                j_->collisionObj();
                if(j_->getArme()->getTirTour()==0)
                    gererAttaqueSurEnnemis(itr->first);

            }
        }
}
void Level::gererCollisionNonJoueur()
{
    map<int,NonJoueur*>::iterator itr;

    for(itr=p_.begin();itr!=p_.end();++itr){
        if(!(m_->estAccessible(itr->second->getPos())))
            itr->second->collisionMap();
    }

        for(itr=p_.begin();itr!=p_.end();++itr){
            if( itr->second->getPos()==j_->getPos()){
                itr->second->collisionObj();


            }
        }
}
void Level::gererMort()
{
        map<int,NonJoueur*>::iterator itr;
        for(itr=p_.begin();itr!=p_.end();++itr){
            if( itr->second->getVie()<=0){
                    p_.erase(itr);
            }
        }

}
bool Level::getChangeLevel()
{
    return changeLevel_;

}
Type_Edge Level::getTypeChange()
{
    return type_change_;
}
void Level::animerProjectile(position a,position b,direction c)
{
    int dx=0,dy=0;
    int retour=-2;
    convertDir(dx,dy,c);


        for(a.y=a.y+dy,a.x=a.x+dx;( a!=b );a.y+=dy,a.x+=dx){
            resetProjectile();
            projectile_[a.y][a.x]=true;
            draw();

            j_->afficheInfoJoueur();
            refresh();
            usleep(250*1000);

        }
    resetProjectile();

}
void Level::resetProjectile()
{
    for(int x=0;x<NX;x++){
        for(int y=0;y<NY;y++){
            projectile_[y][x]=false;
        }
    }

}
